package multiarray;

public class MultiArray<T> {


	public static void main(String[] args) {

	}
	
	int[] dimensionSizes;
	//have to use plain Object here since arrays of a 
	//parameterized type are not allowed in Java	
	Object[] objects;
	
	int numObjects = -1;
	
	public int[] getDimensions() {
		int[] out = new int[dimensionSizes.length];
		for (int i = 0; i<dimensionSizes.length; i++) {
			out[i] = dimensionSizes[i];
		}
		return out;
	}
	
	//have to use raw type cast here since arrays of a 
	//parameterized type are not allowed in Java
	public T getElementAtIndex(int [] positions){
		return (T)objects[getElementIndex(positions)];
	}
	
	public void setElementAtIndex(int [] positions, T object){
		objects[getElementIndex(positions)] = object;
	}	
	
	public T getElementAtRawIndex(int position){
		if(position >= numObjects)
			throw new IllegalArgumentException("illegal position in objects array" +
					" of size " + numObjects + " : " + position);
		return (T)objects[position];
	}
	
	public MultiArray(int[] dimensionSizes){
		this.dimensionSizes = dimensionSizes;
		int numObjects = 1;
		for(int i = 0; i < dimensionSizes.length; i++){
			numObjects = numObjects * dimensionSizes[i];
		}
		objects = new Object[numObjects];
		numObjects = objects.length;
	}

	public int getElementIndex(int [] positions){
		if(positions.length != dimensionSizes.length)
			throw new IllegalArgumentException("incorrect number of dimensions. " +
					"should be " + dimensionSizes.length + ", not " + positions.length);
		for(int i = 1; i < dimensionSizes.length; i++){
			if(positions[i] >= dimensionSizes[i])
				throw new IllegalArgumentException("illegal index in " + i + "th position: " +
						positions[i] + " Should be less than or equal to " + dimensionSizes[i]);
			if(positions[i] < 0)
				throw new IllegalArgumentException("negative index in " + i + "th position: " +
						positions[i]);
		}
		int index = positions[0];
		int factor = 1;
		for(int i = 1; i < dimensionSizes.length; i++){
			factor *= dimensionSizes[i-1];
			index += positions[i] * factor;
		}
		return index;
	}
	
	public int[] getElementPositions(int index){
		int[] positions = new int[dimensionSizes.length];
		int remainder = index;
		int[] factor = new int[dimensionSizes.length];
		factor[0] = dimensionSizes[0];
		for(int i = 1; i < dimensionSizes.length; i++){
			factor[i] = dimensionSizes[i]*factor[i-1];
		}
		if(index > factor[dimensionSizes.length - 1])
			throw new IllegalArgumentException("illegal index in " +
					index + " Should be less than or equal to " + (factor[dimensionSizes.length - 1] ) );
		for(int i = dimensionSizes.length - 1; i > 0; i--){
			positions[i] = remainder / factor[i-1];
			remainder = remainder % factor[i-1];
		}		
		positions[0] = remainder;
		return positions;
	}
	
	
	
	public int getNumObjects() {
		return numObjects;
	}

	public static String printIntArray(int[] positions){
		StringBuffer result = new StringBuffer("{");
		for(int i = 0; i < positions.length - 1; i++){
			result.append(positions[i] + ", ");
		}
		result.append(positions[positions.length - 1] + "}");
		return result.toString();
	}
	
}
